import {
  ChangeDetectorRef,
  Component,
  ElementRef,
  Inject,
  OnInit,
  ViewChild,
} from '@angular/core';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Observable } from 'rxjs';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { map } from 'rxjs/operators';
import {
  MatAutocompleteActivatedEvent,
  MatAutocompleteSelectedEvent,
} from '@angular/material/autocomplete';
import { MatChipInputEvent } from '@angular/material/chips';
import { VulnerabilityProfileTableComponent } from '@routes/vulnerability-profile/vulnerability-profile-table/vulnerability-profile-table.component';
import { VulnerabilityProfileService } from '../../vulnerability-profile.service';
import { TranslateService } from '@ngx-translate/core';
import { updateGridData } from '@common/utils/common.utils';

enum View {
  NAME = 0,
  WITH_FIX = 1,
  WITHOUT_FIX = 2,
}

@Component({
  selector: 'app-vulnerability-profile-table-dialog',
  templateUrl: './vulnerability-profile-table-dialog.component.html',
  styleUrls: ['./vulnerability-profile-table-dialog.component.scss'],
  providers: [VulnerabilityProfileService],
})
export class VulnerabilityProfileTableDialogComponent implements OnInit {
  edit!: boolean;
  view = View.NAME;
  viewText = this.translate.instant('cveProfile.gridHeader.VULNERABILITY');
  View = View;
  separatorKeysCodes: number[] = [ENTER, COMMA];
  namespaceCtrl = new FormControl();
  addOnBlur = true;
  autocompleteTagsOptionActivated = false;
  domainChips: string[] = [];
  filteredDomains!: Observable<string[]>;
  form!: FormGroup;
  loading = false;
  id!: number;
  @ViewChild('namespaceInput') namespaceInput!: ElementRef<HTMLInputElement>;

  constructor(
    private translate: TranslateService,
    private vulnerabilityProfileService: VulnerabilityProfileService,
    public dialogRef: MatDialogRef<VulnerabilityProfileTableComponent>,
    @Inject(MAT_DIALOG_DATA) public data,
    private cd: ChangeDetectorRef
  ) {
    this.filteredDomains = this.namespaceCtrl.valueChanges.pipe(
      map((domain: string) => {
        return domain ? this._filter(domain) : [];
      })
    );
  }

  get images() {
    return this.form.controls.images;
  }

  ngOnInit() {
    this.id = this.data?.profile?.id;
    this.edit = !!this.data?.profile?.name;
    let withFixDays = null;
    let withoutFixDays = null;
    let name = this.data?.profile?.name;
    if (name === '_RecentVulnWithoutFix') {
      withoutFixDays = this.data?.profile?.days;
    } else if (name === '_RecentVuln') {
      withFixDays = this.data?.profile?.days;
    }
    this.domainChips = this.data?.profile?.domains || [];
    this.form = new FormGroup({
      images: new FormControl(this.data?.profile?.images || []),
      comment: new FormControl(this.data?.profile?.comment || null),
      name: new FormControl(name, Validators.required),
      withFix: new FormControl({ value: withFixDays, disabled: true }, [
        Validators.required,
        Validators.pattern('^[0-9]*$'),
        Validators.max(410065408),
      ]),
      withoutFix: new FormControl({ value: withoutFixDays, disabled: true }, [
        Validators.required,
        Validators.pattern('^[0-9]*$'),
        Validators.max(410065408),
      ]),
    });
    if (name === '_RecentVulnWithoutFix') {
      this.changeView(View.WITHOUT_FIX);
    } else if (name === '_RecentVuln') {
      this.changeView((this.view = View.WITH_FIX));
    }
    this.cd.markForCheck();
  }

  changeView(num: View) {
    switch (num) {
      case View.NAME: {
        this.viewText = this.translate.instant(
          'cveProfile.gridHeader.VULNERABILITY'
        );
        this.form.controls.name.reset();
        this.form.controls.name.enable();
        this.form.controls.withFix.disable();
        this.form.controls.withoutFix.disable();
        break;
      }
      case View.WITH_FIX: {
        this.viewText = this.translate.instant(
          'cveProfile.gridHeader.REPORTED_DAYS'
        );
        this.form.controls.withFix.reset();
        this.form.controls.withFix.enable();
        this.form.controls.name.disable();
        this.form.controls.withoutFix.disable();
        break;
      }
      case View.WITHOUT_FIX: {
        this.viewText = this.translate.instant(
          'cveProfile.gridHeader.REPORTED_DAYS_WITHOUT_FIX'
        );
        this.form.controls.withoutFix.reset();
        this.form.controls.withoutFix.enable();
        this.form.controls.name.disable();
        this.form.controls.withFix.disable();
        break;
      }
    }
    this.view = num;
  }

  optionActivated(event: MatAutocompleteActivatedEvent): void {
    if (event.option) {
      this.autocompleteTagsOptionActivated = true;
    }
  }

  selected(event: MatAutocompleteSelectedEvent): void {
    this.namespaceInput.nativeElement.value = '';
    if (this.domainChips.includes(event.option.viewValue)) {
      return;
    }
    this.domainChips.push(event.option.value);
    this.autocompleteTagsOptionActivated = false;
    this.namespaceCtrl.setValue(null);
  }

  addNamespace(event: MatChipInputEvent): void {
    const value = (event.value || '').trim();
    if (
      !this.autocompleteTagsOptionActivated &&
      value &&
      !this.domainChips.includes(value)
    ) {
      this.domainChips.push(value);
    }
    if (event.chipInput) {
      event.chipInput.clear();
    }
    this.namespaceCtrl.setValue(null);
  }

  removeNamespace(domain: string): void {
    const chipIdx = this.domainChips.indexOf(domain);
    if (chipIdx >= 0) {
      this.domainChips.splice(chipIdx, 1);
    }
  }

  addImage(event: MatChipInputEvent): void {
    const input = event.input;
    const value = event.value;
    if ((value || '').trim()) {
      this.images.setValue([...this.images.value, value.trim()]);
      this.images.updateValueAndValidity();
    }
    if (input) {
      input.value = '';
    }
  }

  removeImage(image: string): void {
    const index = this.images.value.indexOf(image);

    if (index >= 0) {
      this.images.value.splice(index, 1);
      this.images.updateValueAndValidity();
    }
  }

  onNoClick(): void {
    this.dialogRef.close();
  }

  confirm() {
    this.loading = true;
    let name = '',
      days = 0;
    if (this.form.controls.name.enabled) {
      name = this.form.controls.name.value;
    } else if (this.form.controls.withFix.enabled) {
      name = '_RecentVuln';
      days = parseInt(this.form.controls.withFix.value);
    } else if (this.form.controls.withoutFix.enabled) {
      name = '_RecentVulnWithoutFix';
      days = parseInt(this.form.controls.withoutFix.value);
    }
    const config = {
      entries: [
        {
          name,
          days,
          id: this.id,
          comment: this.form.controls.comment.value || '',
          images: this.form.controls.images.value,
          domains: this.domainChips,
        },
      ],
      name: 'default',
    };
    if (this.edit) {
      this.vulnerabilityProfileService
        .updateEntry(config.entries[0], 'default')
        .subscribe({
          next: () => {
            updateGridData(
              this.data.rowData,
              config.entries,
              this.data.gridApi,
              'id',
              'edit'
            );
            this.dialogRef.close(true);
          },
          complete: () => (this.loading = false),
        });
    } else {
      this.vulnerabilityProfileService.addEntry(config).subscribe({
        next: () => {
          this.dialogRef.close(true);
        },
        complete: () => (this.loading = false),
      });
    }
  }

  private _filter(value: string): string[] {
    const filterValue = value.toLowerCase();
    return this.data.domains
      .filter(domain => !this.domainChips.includes(domain))
      .filter(domain => domain.toLowerCase().includes(filterValue));
  }
}
